﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FCS
{
    #region InfiniteList<T>

    abstract class InfiniteList<T> : FunList<T>
    {
        protected T From { get; private set; }
        protected T To { get; private set; }
        protected bool HasTo { get; private set; }

        protected InfiniteList(T from)
        {
            From = from;
            HasTo = false;
        }

        protected InfiniteList(T from, T to)
        {
            From = from;
            To = to;
            HasTo = true;
        }

        public override IEnumerator<T> GetEnumerator()
        {
            if (Terminate())
                yield break;

            T val = From;
            yield return val;

            while (!HasTo || !val.Equals(To))
            {
                val = GetNext(val);
                yield return val;
            }
        }

        public abstract T GetNext(T v);

        protected virtual bool Terminate()
        {
            return false;
        }
    }

    #endregion

    #region IntList

    sealed class IntList : InfiniteList<int>
    {
        public IntList(int from)
            : base(from)
        {
        }

        public IntList(int from, int to)
            : base(from, to)
        {
        }

        public override IEnumerator<int> GetEnumerator()
        {
            if (Terminate())
                yield break;

            int val = From;
            yield return val;

            if (HasTo)
            {
                while (val != To)
                {
                    val++;
                    yield return val;
                }
            }
            else
            {
                while (true)
                {
                    val++;
                    yield return val;
                }
            }
        }

        public override int GetNext(int v)
        {
            return v + 1;
        }

        protected override bool Terminate()
        {
            return this.HasTo && this.From > this.To;
        }
    }

    #endregion

    #region FromArrayList<T>

    sealed class FromArrayList<T> : FunList<T>
    {
        private T[] Items { get; set; }

        public FromArrayList(T[] items)
        {
            Items = items;
        }

        #region IEnumerable<T> Members

        public override IEnumerator<T> GetEnumerator()
        {
            foreach (T t in Items)
            {
                yield return t;
            }
        }

        #endregion
    }

    #endregion

    #region NonLazy<T>

    sealed class NonLazy<T> : FunList<T>
    {
        private List<T> Items { get; set; }

        public NonLazy()
        {
            Items = new List<T>();
        }

        public void Add(T val)
        {
            Items.Add(val);
        }

        public void AddRange(IFunList<T> list)
        {
            Items.AddRange(list);
        }

        #region IEnumerable<T> Members

        public override IEnumerator<T> GetEnumerator()
        {
            return Items.GetEnumerator();
        }

        #endregion
    }

    #endregion

    #region Empty<T> and EmptyLL<T>

    sealed class Empty<T> : FunList<T>
    {
        public Empty()
        {
        }

        public override IEnumerator<T> GetEnumerator()
        {
            yield break;
        }
    }

    sealed class EmptyLL<T> : FunList<IFunList<T>>
    {
        public EmptyLL()
        {
        }

        public override IEnumerator<IFunList<T>> GetEnumerator()
        {
            yield return new Empty<T>();
        }
    }

    #endregion
}
